/**
 * @Author       : Mo 2427995270@qq.com
 * @Date         : 2022-08-19 10:20:43
 * @LastEditTime : 2025-06-13 12:04:51
 * @FilePath     : \GD32F407_BL\mobl\hal_driver\hal_uart.h
 * @Description  : uart驱动
 * @Version      : V1.00
 * @History      : V1.00 初版
 * @Note         : 1、使用FreeRtos的软件定时器，需保证串口中断受FreeRtos管理
 *                 2、使用uart_receiving_cb_t实现超时接收完成时，如使用了uart_recv函数，则须在接受完成函数中将 rxbuf地址赋值给pRx;
 */


#ifndef __hal_uart_H__
#define __hal_uart_H__

/***************************************Includes***********************************/
#include "ll_uart.h"
#include "os_config.h"
#include <stdint.h>

#if USE_OS == OS_FREERTOS
#include "FreeRTOS.h"
// #include "task.h"
#include "timers.h"
#include "semphr.h"
#endif

/***************************************Macros***********************************/

// gbk编码的printf支持
#if !defined(UART_HAL_PRINTF_SUPPORT_GBK)
#define UART_HAL_PRINTF_SUPPORT_GBK 0
#endif

// 使用systick完成接收超时 在系统不可用时可使用
#if !defined(UART_HAL_USE_SYSTICK)
#define UART_HAL_USE_SYSTICK 0
#endif

#if UART_HAL_USE_SYSTICK
#include "hal_systick.h"
#endif

// 获取接收数据结构
#define uart_hal_get_usr_recv(uart) ((uart)->usr_recv)
// 获取发送状态 非零发送中
#define uart_hal_get_tx_status(uart) uart_ll_get_tx_status(&((uart)->uart))
// 获取接收数据缓冲区
#define uart_hal_get_rxbuf(uart) ((uart)->rxbuf)
// 获取接收数据缓冲区大小
#define uart_hal_get_rxbuf_size(uart) ((uart)->rxbuf_size)
// 获取发送数据缓冲区
#define uart_hal_get_txbuf(uart) ((uart)->txbuf)
// 获取发送数据缓冲区大小
#define uart_hal_get_txbuf_size(uart) ((uart)->txbuf_size)
// 获取接收数据长度
#define uart_hal_get_rxlen(uart) ((uart)->rx_len)

/***************************************Variables***********************************/
struct uart_hal;
typedef struct uart_hal uart_hal_t;

typedef struct {
    uint8_t *buf; // 接受数据的缓冲区
    int size;     // 缓冲区大小
    int len;      // 接收到的数据长度
} uart_recv_t;
// 接收中回调
typedef void (*uart_receiving_cb_t)(uart_hal_t *utt, uint16_t data, void *arg);
// 接收完成回调 仅支持GD32F4超时完成
typedef void (*uart_received_completed_cb_t)(uart_hal_t *utt, uart_recv_t *urt, void *arg);

struct uart_hal {
    uart_ll_t uart;
    uint8_t *rxbuf;      // 接受缓存区指针 , 不要更改该指针
    uint8_t *txbuf;      // 发送缓冲区指针，uart_printf使用，不用可给NULL
    uint32_t rxbuf_size; // 接受缓冲区大小
    uint32_t txbuf_size; // 发送缓冲区大小

    uint32_t rxbuf_len; // 接受缓冲区已接受的数据长度 byte
    uint8_t *pRx;       // 接收过程指针
    uint32_t rx_len;    // 接受结束的数据长度
#if USE_OS == OS_FREERTOS
    TimerHandle_t timer;      // 接受超时定时器
    TickType_t overtime_ms;   // 超时 ms
    TaskHandle_t task_handle; // 任务句柄，接收超时后将向task_handle发送任务通知
    SemaphoreHandle_t mutex;
#endif
#if UART_HAL_USE_SYSTICK
    systick_hal_t systick;
#endif
    uart_receiving_cb_t receiving_cb;               // 接收中回调
    uart_received_completed_cb_t rece_completed_cb; // 接收完成回调
    void *arg;                                      // 用户参数
    // 用户接受数据的结构，如果设置，接受完成后将从pRxbuf缓冲区复制到usr_recv的缓冲区，需保证空间足够，不够会导致接收不完整;
    // 如果不设置，usr_recv将自动指向pRxbuf
    uart_recv_t usr_recv;
};


/***************************************Functions***********************************/
/**
 * @brief 初始化uart
 * @param  utt              
 * @param  uct              配置文件
 * @return int 0成功 -1失败
 * @note null
 */
int uart_hal_init(uart_hal_t *utt, uint8_t *rxbuf, uint32_t rxbuf_size, uint8_t *txbuf, uint32_t txbuf_size);
/**
 * @brief 设置接收中回调函数
 * @param  utt
 * @param  receiving_cb     接收中回调，可重置定时器实现超时或接收数据
 * @param  arg              用户参数
 * @return int 0
 * @note null
 */
int uart_hal_set_receiving_cb(uart_hal_t *utt, uart_receiving_cb_t cb, void *arg);
/**
 * @brief 设置接收完成回调函数 仅软件定时器\GD32F407超时中断\systick定时器支持，或自行实现超时完成调用uart_hal_rx_done_handler
 * @param  utt              
 * @param  cb               接收完成回调
 * @param  arg              用户参数
 * @return int 0
 * @note null
 */
int uart_hal_set_received_completed_cb(uart_hal_t *utt, uart_received_completed_cb_t cb, void *arg);
#if USE_OS == OS_FREERTOS

/**
 * @brief 创建定时器
 * @param  utt
 * @param  name             定时器名
 * @param  overtime_ms      超时时间
 * @param  tht              超时后要通知的任务，任务通知值是uart_recv_t结构的指针，用来传递数据
 * @return int 0成功 -1失败
 * @note null
 */
int uart_hal_create_timer(uart_hal_t *utt, const char *name, uint32_t overtime_ms, TaskHandle_t tht);
/**
 * @brief 删除定时器
 * @param  utt
 * @return int
 * @note null
 */
int uart_hal_delete_timer(uart_hal_t *utt);
#endif

#if UART_HAL_USE_SYSTICK

/**
 * @brief 创建systick定时器
 * @param  uht              句柄
 * @param  name             定时器名
 * @param  overtime_ms      接收超时时间
 * @return int 0成功 -1未初始化systick_hal
 * @note null
 */
int uart_hal_create_systick(uart_hal_t *uht, const char *name, uint32_t overtime_ms);
/**
 * @brief 删除定时器
 * @param  uht              
 * @return int 0成功 -1失败
 * @note null
 */
int uart_hal_delete_systick(uart_hal_t *uht);
#endif

/**
 * @brief 设置用户接收结构
 * @param  utt
 * @param  buf              用于接收数据的缓冲区
 * @param  size             缓冲区大小
 * @note null
 */
void uart_hal_set_usr_recv(uart_hal_t *utt, void *buf, int size);
void uart_hal_printf(uart_hal_t *utt, const char *fmt, ...);
void uart_hal_puts(uart_hal_t *utt, char *str);
void uart_hal_putbuf(uart_hal_t *utt, uint8_t *buf, uint32_t len_byte);
#if UART_HAL_PRINTF_SUPPORT_GBK
/**
 * @brief 打印函数 编码gbk
 * @param  utt              
 * @param  gbk              用于编码转换的buf 存转为GBK的数据
 * @param  size             buf大小
 * @param  fmt              
 * @param  ...              
 * @note null
 */
void uart_hal_printf_to_gbk(uart_hal_t *utt, void *gbk, int size, const char *fmt, ...);
#endif
/**
 * @brief 发送一个字节
 * @param  utt
 * @param  Sda              数据
 * @note null
 */
void uart_hal_write_byte(uart_hal_t *utt, uint16_t Sda);
/**
 * @brief 字符串拷贝 遇到chr时停止，如果剩余空间允许，以'\0'结尾
 * @param  buf
 * @param  src
 * @param  chr
 * @param  size
 * @return int 拷贝的长度
 * @note null
 */
int uart_hal_strcasecpy(char *buf, const char *src, int chr, int size);
/**
 * @brief 在字符串中查找子串
 * @param  haystack         被查找
 * @param  needle           想查找的
 * @param  len              haystack长度
 * @return char* NULL或子串指针
 * @note null
 */
char *uart_hal_strnstr(const char *haystack, const char *needle, uint32_t len);
/**
 * @brief 从接收缓冲区读取
 * @param  utt
 * @param  buf              out数据
 * @param  recvlen           读取的字节数
 * @param  timeout_ms        超时时间
 * @return int
 * @note 递增的，读取超时返回-1 ，每次新接收到数据，指针就指向接收缓冲区头
 */
int uart_hal_recv(uart_hal_t *utt, void *buf, int recvlen, int timeout_ms);
/**
 * @brief UART中断处理函数
 * @param  utt
 * @note null
 */
void uart_hal_rx_handler(uart_hal_t *uht, uint32_t data);
/**
 * @brief UART接收完成处理函数(自行实现的接收完成需调用)
 * @param  uht
 * @note null
 */
void uart_hal_rx_done_handler(uart_hal_t *uht);
/***************************************statement***********************************/

#endif
/* [] END OF FILE */
